using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace MyNamespace
{
    abstract public class ItemBase
    {
        #region Contructor
        public ItemBase(SPListItem p_item)
        {
            if (thisTypeContentTypeName != "" && p_item.ContentType != null)
            {
                if (p_item.ContentType == null) throw new PointBridgeEx(string.Format("Attempting to initialize a wrapper for Content Type '{0}' using SPListItem of Content Type '{1}'", thisTypeContentTypeName, "null"));
                if (p_item.ContentType.Name != thisTypeContentTypeName) throw new PointBridgeEx(string.Format("Attempting to initialize a wrapper for Content Type '{0}' using SPListItem of Content Type '{1}'", thisTypeContentTypeName, p_item.ContentType.Name));
            }
            _item = p_item;
        }
        #endregion

        #region Public Methods
        abstract public void Validate();
        public void UpdateWithValidate()
        {
            Validate();
            UpdateNoValidate();
        }
        public void UpdateNoValidate()
        {
            _item.Update();
        }
        public void Delete()
        {
            _item.Delete();
        }
        #endregion

        #region Accessors and Mutators
        public SPListItem item
        {
            get { return _item; }
        }

        public int itemID
        {
            get { return _item.ID; }
        }

        public SPAttachmentCollection Attachments
        {
            get { return _item.Attachments; }
        }
        #endregion

        #region Private Methods
        protected void ValidateItemContentTypeAgainstParentList()
        {
            if (_item.ContentType != null && _item.ContentType.Name != "")
            {
                try
                {
                    if (_item.ParentList.ContentTypes[_item.ContentType.Name] == null) throw new Exception("");
                }
                catch (Exception)
                {
                    throw new PointBridgeEx("SPListItem content type is '{0}' while its ParentList does not support that content type");
                }
            }
        }
        protected void ValidateFields(SPFieldCollection fields)
        {
            foreach (SPField field in fields) ValidateField(field);
        }
        protected void ValidateField(SPField columnDef)
        {
            string lookupName = ConvertSPNameToLookupStr(columnDef);
            object columnVal = _item[lookupName];

            //first check if it is empty and whether it is allowed
            if (columnDef.Required == true)
            {
                switch (columnDef.Type)
                {
                    //for multi-selects we do spewcial cases
                    case SPFieldType.MultiChoice:
                        SPFieldMultiChoice multiChoiceColumnDef = (SPFieldMultiChoice)columnDef;
                        if (MultiChoice.GetCountFromSPRepresentation(columnVal) == 0) throw new PointBridgeEx(string.Format("MultiChoice validation failed. Column \"{0}\" is required but is not set to null or no value.", lookupName));
                        break;
                    case SPFieldType.Lookup:
                        SPFieldLookup lookupColumnDef = (SPFieldLookup)columnDef;
                        if (lookupColumnDef.AllowMultipleValues == true)
                        {
                            if (MultiLookup.GetCountFromSPRepresentation(columnVal) == 0) throw new PointBridgeEx(string.Format("MultiLookup validation failed. Column \"{0}\" is required but is not set to null or no value.", lookupName));
                        }
                        else
                        {
                            goto default;
                        }
                        break;
                    case SPFieldType.User:
                        SPFieldUser userColumnDef = (SPFieldUser)columnDef;
                        if (userColumnDef.AllowMultipleValues == true)
                        {
                            if (MultiUser.GetCountFromSPRepresentation(columnVal) == 0) throw new PointBridgeEx(string.Format("MultiUser validation failed. Column \"{0}\" is required but is not set to null or no value.", lookupName));
                        }
                        else
                        {
                            goto default;
                        }
                        break;
                    default:
                        if (columnVal == null) throw new PointBridgeEx(string.Format("SPFieldType.{0} validation failed. Column \"{1}\" is required but is set to null.", columnDef.Type.ToString(), lookupName));
                        if (columnVal.GetType() == typeof(string))
                        {
                            string strColumnVal = (string)columnVal;
                            if (strColumnVal.Trim().Length == 0) throw new PointBridgeEx(string.Format("SPFieldType.{0} validation failed. Column \"{1}\" is required but is set to an empty string.", columnDef.Type.ToString(), lookupName));
                        }
                        break;
                }
            }

            if (_item[lookupName] == null) return; //if field is null, there is no data to validate

            //validate content
            switch (columnDef.Type)
            {
                case SPFieldType.Text:
                    SPFieldText textColumnDef = (SPFieldText)columnDef;
                    string textVal = (string)columnVal;
                    if (textVal.Length > textColumnDef.MaxLength) throw new PointBridgeEx(string.Format("Validation failed. Column \"{0}\" length exceeds maximum length allowed for this column.", lookupName));
                    break;
                case SPFieldType.Note:
                    SPFieldMultiLineText noteColumnDef = (SPFieldMultiLineText)columnDef;
                    string noteVal = (string)columnVal;
                    //No validation here
                    break;
                case SPFieldType.URL:
                    SPFieldUrl urlColumnDef = (SPFieldUrl)columnDef;
                    string urlVal = (string)columnVal;
                    //No validation here. maybe urlColumnDef.UnlimitedLengthInDocumentLibrary???
                    break;
                case SPFieldType.Guid:
                    SPField guidColumnDef = (SPField)columnDef;
                    string guidVal = (string)columnVal;
                    //No validation here
                    break;
                case SPFieldType.File:
                    SPFieldFile fileColumnDef = (SPFieldFile)columnDef;
                    string fileVal = (string)columnVal;
                    //No validation here
                    break;
                case SPFieldType.ModStat:
                    SPFieldModStat modStatColumnDef = (SPFieldModStat)columnDef;
                    //No validation here, validation is done within the object
                    break;
                case SPFieldType.Currency:
                    SPFieldCurrency currencyColumnDef = (SPFieldCurrency)columnDef;
                    double currencyVal = (double)columnVal;
                    if (currencyVal < currencyColumnDef.MinimumValue || currencyVal > currencyColumnDef.MaximumValue) throw new PointBridgeEx(string.Format("Validation failed. Column \"{0}\" value ({1}) does not fall within allowed range of {2}-{3}.", lookupName, currencyVal, currencyColumnDef.MinimumValue, currencyColumnDef.MaximumValue));
                    break;
                case SPFieldType.Number:
                    SPFieldNumber numberColumnDef = (SPFieldNumber)columnDef;
                    double numberVal = (double)columnVal;
                    if (numberVal < numberColumnDef.MinimumValue || numberVal > numberColumnDef.MaximumValue) throw new PointBridgeEx(string.Format("Validation failed. Column \"{0}\" value ({1}) does not fall within allowed range of {2}-{3}.", lookupName, numberVal, numberColumnDef.MinimumValue, numberColumnDef.MaximumValue));
                    break;
                case SPFieldType.Integer:
                    SPFieldNumber intColumnDef = (SPFieldNumber)columnDef;
                    int intColumnVal = (int)columnVal;
                    if (intColumnVal < intColumnDef.MinimumValue || intColumnVal > intColumnDef.MaximumValue) throw new PointBridgeEx(string.Format("Validation failed. Column \"{0}\" value ({1}) does not fall within allowed range of {2}-{3}.", lookupName, intColumnVal, intColumnDef.MinimumValue, intColumnDef.MaximumValue));
                    break;
                case SPFieldType.Counter:
                    SPField counterColumnDef = (SPField)columnDef;
                    int counterColumnVal = (int)columnVal;
                    //No validation here
                    break;
                case SPFieldType.Boolean:
                    SPFieldBoolean booleanColumnDef = (SPFieldBoolean)columnDef;
                    bool booleanVal = (bool)columnVal;
                    break;
                case SPFieldType.Attachments:
                    SPFieldAttachments attachmentsColumnDef = (SPFieldAttachments)columnDef;
                    bool attchmentsColumnVal = (bool)columnVal;
                    break;
                case SPFieldType.DateTime:
                    SPFieldDateTime dateTimeColumnDef = (SPFieldDateTime)columnDef;
                    DateTime dateTimeVal = (DateTime)columnVal;
                    //No validation here
                    break;
                case SPFieldType.ContentTypeId:
                    SPField contentTypeIdColumnDef = (SPField)columnDef;
                    SPContentTypeId contentTypeIdVal = (SPContentTypeId)columnVal;
                    //No validation here
                    break;
                case SPFieldType.Choice:
                    SPFieldChoice choiceColumnDef = (SPFieldChoice)columnDef;
                    //No validation here, validation is done within the object
                    break;
                case SPFieldType.MultiChoice:
                    SPFieldMultiChoice multiChoiceColumnDef = (SPFieldMultiChoice)columnDef;
                    //No validation here, validation is done within the object
                    break;
                case SPFieldType.Lookup:
                    SPFieldLookup lookupColumnDef = (SPFieldLookup)columnDef;
                    //No validation here, validation is done within the object
                    break;
                case SPFieldType.User:
                    SPFieldUser userColumnDef = (SPFieldUser)columnDef;
                    //No validation here, validation is done within the object
                    break;
                case SPFieldType.Computed:
                    SPFieldComputed computedColumnDef = (SPFieldComputed)columnDef;
                    //No validation here, value could be any type
                    break;
                case SPFieldType.Invalid:
                    //this could be Html field or somehting else. Can't validate
                    break;
                //for these there is no validation and caset testing is problematic
                case SPFieldType.AllDayEvent:
                case SPFieldType.Recurrence:
                case SPFieldType.CrossProjectLink:
                case SPFieldType.Calculated:
                case SPFieldType.ThreadIndex:
                default:
                    break;
            }
        }
        public string ConvertSPNameToLookupStr(SPField field)
        {
            if (thisTypeContentTypeName != null && thisTypeContentTypeName != "") return field.StaticName.Replace("_x0020_", " ");
            else return field.InternalName;
        }
        #endregion

        #region Constants
        public abstract string thisTypeContentTypeName
        {
            get;
        }
        #endregion

        #region Internal Fields
        protected SPListItem _item;
        #endregion

    }
}
